//
//  Problem690.swift
//  TestProject
//
//  Created by 武侠 on 2021/6/4.
//  Copyright © 2021 zhulong. All rights reserved.
//

import UIKit

/*
 690. 员工的重要性
 给定一个保存员工信息的数据结构，它包含了员工 唯一的 id ，重要度 和 直系下属的 id 。

 比如，员工 1 是员工 2 的领导，员工 2 是员工 3 的领导。他们相应的重要度为 15 , 10 , 5 。那么员工 1 的数据结构是 [1, 15, [2]] ，员工 2的 数据结构是 [2, 10, [3]] ，员工 3 的数据结构是 [3, 5, []] 。注意虽然员工 3 也是员工 1 的一个下属，但是由于 并不是直系 下属，因此没有体现在员工 1 的数据结构中。

 现在输入一个公司的所有员工信息，以及单个员工 id ，返回这个员工和他所有下属的重要度之和。
 示例：
     输入：[[1, 5, [2, 3]], [2, 3, []], [3, 3, []]], 1
     输出：11
     解释：
     员工 1 自身的重要度是 5 ，他有两个直系下属 2 和 3 ，而且 2 和 3 的重要度均为 3 。因此员工 1 的总重要度是 5 + 3 + 3 = 11 。
 提示：
     一个员工最多有一个 直系 领导，但是可以有多个 直系 下属
     员工数量不超过 2000 。
 */
public class Employee {
    public var id: Int
    public var importance: Int
    public var subordinates: [Int]
    public init(_ id: Int, _ importance: Int, _ subordinates: [Int]) {
        self.id = id
        self.importance = importance
        self.subordinates = subordinates
    }
}

@objcMembers class Problem690: NSObject {
    func solution() {
        let list = [Employee(1, 5, [2, 3]), Employee(2, 3, []), Employee(3, 3, [])]
        print(getImportance(list, 1))
    }
    
    /*
     0: 哈希建树
     1: 先找到该员工 ： DFS / BFS
     2: 统计该员工所有下属的和: DFS / BFS
     */
    func getImportance(_ employees: [Employee], _ id: Int) -> Int {
        var root: Employee? = nil
        var map:[Int: Employee] = [:]
        for employ in employees {
            map[employ.id] = employ
            if employ.id == id {
                root = employ
            }
        }
       return getImpotanceBFS(map, root)
    }
    
    /*
     DFS 深度优先搜索 递归
     */
    func getImpotanceDFS(_ map: [Int:Employee], _ root: Employee?) -> Int {
        if root == nil {
            return 0
        }
        var sum = root!.importance
        for cid in root!.subordinates {
            sum += getImpotanceDFS(map, map[cid])
        }
        return sum
    }
    
    /*
     BFS 广度优先搜索
     */
    func getImpotanceBFS(_ map: [Int:Employee], _ root: Employee?) -> Int {
        if root == nil {
            return 0
        }
        
        var sum = 0
        var node: Employee
        var list:[Employee] = [root!]
        while list.isEmpty == false {
            node = list.removeFirst()
            sum += node.importance
            list.append(contentsOf: node.subordinates.map({ id in
                return map[id]!
            }))
        }
        
        return sum
    }
    
}
